<?php

namespace app\site\service;

use app\admin\service\site\SiteUserRuleService;
use app\common\exception\MiException;
use app\extend\MiAuth;
use app\model\auth\AdminGroup;
use app\model\auth\AdminRule;
use app\model\site\Site;
use app\model\site\SiteUser;
use app\model\site\SiteUserRule;
use thans\jwt\facade\JWTAuth;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;

class SiteAuthService
{

    private static ?self $_instance = null;

    public static function instance(): self
    {
        if (!self::$_instance){
            self::$_instance = new self();
        }
        return self::$_instance;
    }

//   废弃 protected string $tokenCachePre = 'site_';
//废弃
//    public function getToken(){
//        return request()->header('mi-token');
//    }

//    public function checkToken(): bool
//    {
//        $token = $this->getToken();
//        $cacheToken = Cache::get($this->tokenCachePre.$token);
//        if ($cacheToken){
//            return true;
//        }
//        return false;
//    }

//    public function setLoginToken($token, $adminId){
//        Cache::set($this->tokenCachePre.$token, $adminId, 60*60*24);
//    }

//    public function logout(){
//        Cache::delete($this->tokenCachePre.$this->getToken());
//    }

    /**
     * 获取登录用户的id
     * **注意** 此方法绝对不能在构造函数中使用，因为【构造函数】是在【中间件】之前调用，
     * 【登录验证中间件】会验证令牌的有效性，而本函数必须在令牌验证之后执行，所以不能在中间件之前调用
     * @throws MiException
     */
    public function getLoginId(): int
    {

        try {
            $payload = JWTAuth::auth(); //可验证token, 并获取token中的payload部分
            $id = $payload['id']; //可以继而获取payload里自定义的字段，比如uid

        } catch (\Exception $e){   // 捕获异常
            throw new MiException('令牌过期', TOKEN_EXPIRE_CODE);
        }
        return $id;
    }

    /**
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws MiException
     */
    public function getLoginInfo(){
        $id = $this->getLoginId();
        $info = SiteUser::find($id);
        if (!$info){
            throw new MiException("没有获取到管理员信息");
        }
        return $info;
    }

    /** 当前站点的id
     * @throws MiException
     */
    public function getSiteId(){
        $payload = JWTAuth::auth(); //可验证token, 并获取token中的payload部分
        $id = $payload['site_id']; //可以继而获取payload里自定义的字段，比如uid

        return $id;
    }

    /**
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     * @throws MiException
     */
    public function getSite(){
        return Site::find($this->getSiteId());
    }

    /**
     * 获取登录用户的所有目录和菜单
     * @param $adminId
     * @return void
     */
    public function getLoginMenus(){
        $query = SiteUserRule::where('rule_type', '<>', 3)
            ->where('status', 1)
            ->order('sort desc');

        $adminId = $this->getLoginId();
        $super = config('app.super_admin');

        if($adminId != $super){ // 不是超级管理员
            // 获取用户拥有的所有权限规则ids[]
            $auth = MiAuth::instance();
            $groups = $auth->getGroups($adminId);
            if (count($groups) == 0){
                $gids = [];
            }else{
                $gids = Si::where('id', $groups[0]['group_id'])->limit(1)->value('rules');
            }

            // 添加条件
            $query->whereIn('id', $gids);
        }

        $auths = $query->select();

        // 组装二维数组
        return (new SiteUserRuleService())->childrenTree($auths);
    }


    /**
     * 获取登录用户的所有权限规则（包含目录、菜单、权限）
     * @return array
     */
    public function getLoginRules(): array
    {
        // 查询前的准备(基础查询条件)
        $query = AdminRule::where('status', 1)->where('rule_type', 3)
            ->order('sort desc')
            ->cache(true, 60);

        $super = config('app.super_admin');
        $adminId = $this->getLoginId();

        if( $adminId != $super){ // 不是超级管理员
            // 获取用户拥有的所有权限规则ids[]
            $auth = MiAuth::instance();
            $groups = $auth->getGroups($adminId);
            if (count($groups) == 0){
                $gids = [];
            }else{
                $gids = AdminGroup::where('id', $groups[0]['group_id'])->limit(1)->value('rules');
            }
            // 添加条件
            $query = $query->whereIn('id', $gids);
        }

        return $query->column('name');
    }


    /**
     * 验证当前登陆admin的权限
     * @param $rule
     * @return bool
     * 验证admin权限
     * @throws MiException
     */
    function checkLoginAuth($rule): bool
    {

        // 获取当前用户
        $adminId = $this->getLoginId();

        // 超级管理员不验证权限
        $super = Config::get('app.super_admin');
        if($super == $adminId){
            return true;
        }

        // 验证权限
        $auth = MiAuth::instance();
        // check中会将所有字母转为小写
        return $auth->check($rule, $adminId);
    }

}
